package com.suncm3kw.chatgpt.service;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

import org.springframework.http.MediaType;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import com.suncm3kw.chatgpt.StaticValue;
import com.suncm3kw.chatgpt.entity.SseEmitterUTF8;
import com.suncm3kw.chatgpt.listener.SseCompleteListener;

import lombok.extern.slf4j.Slf4j;

@Service("baseChatGptService")
@Slf4j
public class BaseChatGptService {

	private static final Map<String, SseEmitterUTF8> SSE_CACHE = new HashMap<>();

	public SseEmitterUTF8 getConn(String sseId) {
		if (SSE_CACHE.isEmpty()) {
			return createEmitter(sseId);
		} else {
			final SseEmitterUTF8 sseEmitter = SSE_CACHE.get(sseId);
			if (sseEmitter != null) {
				return sseEmitter;
			} else {
				return createEmitter(sseId);
			}
		}
	}

	public SseEmitterUTF8 complete(String sseId, String data) throws IOException {
		try {
			SseEmitterUTF8 emitter = getConn(sseId);
			if (emitter != null) {
				emitter.send(data);
				emitter.complete();
				emitter.setDone(true);// 数据发送完成后，关闭连接
			}
			return emitter;
		} finally {
			SSE_CACHE.remove(sseId);
		}
	}

	private SseEmitterUTF8 createEmitter(String clientId) {
		// 设置连接超时时间，需要配合配置项 spring.mvc.async.request-timeout: 600000 一起使用
		final SseEmitterUTF8 emitter = new SseEmitterUTF8(clientId);
		emitter.onCompletion(() -> {
			log.info("连接已关闭，正准备释放，clientId = {}", clientId);
			SSE_CACHE.remove(clientId);
			emitter.setDone(true);
		});
		// 注册异常回调，调用 emitter.completeWithError() 触发
		emitter.onTimeout(() -> {
			log.info("连接超时，正准备关闭，clientId = {}", clientId);
			SSE_CACHE.remove(clientId);
			emitter.setDone(true);
		});
		SSE_CACHE.put(clientId, emitter);
		return emitter;
	}

	@Async
	public void sentSseMessageOrigin(SseEmitterUTF8 emitter, String ApiChatHead,  String jsonData,
			SseCompleteListener listener,boolean isOllama) throws IOException {
		String gptHttpHead=ApiChatHead+(isOllama?"/api/chat":"/v1/chat/completions");
		log.info("发给GPT的数据：{}", jsonData);
		log.info("发给Url：{},key={}",gptHttpHead );
		InputStream is = null;
		BufferedReader reader = null;
		emitter.setDone(false);
		try {
			URLConnection urlConnection = new URL(gptHttpHead).openConnection();
			urlConnection.setRequestProperty("Method", "POST");
			urlConnection.setConnectTimeout((int)StaticValue.SSE_TIMEOUT);
			urlConnection.setReadTimeout((int)StaticValue.SSE_TIMEOUT);
			urlConnection.setDoOutput(true);
			urlConnection.setDoInput(true);
			urlConnection.setUseCaches(true);
			urlConnection.setRequestProperty("Connection", "Keep-Alive");
			urlConnection.setRequestProperty("Content-Type", "application/json");
			urlConnection.setRequestProperty("User-Agent",StaticValue.UserAgent);

			OutputStream outputStream = urlConnection.getOutputStream();
			outputStream.write(jsonData.getBytes(StandardCharsets.UTF_8));
			outputStream.flush();
			outputStream.close();

			is = new BufferedInputStream(urlConnection.getInputStream());
			reader = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
			String line = "";
			StringBuilder stringBuilder = new StringBuilder();
			while ((line = reader.readLine()) != null) {
				log.info("gpt返回的流数据:{}",line);
				sseSendMessageOrigin(line, emitter);
			}
			listener.completeSuscc(stringBuilder.toString(), "");
			emitter.complete();
			emitter.setDone(true);// 数据发送完成后，关闭连接
		} catch (Exception e) {
			log.info("SSE @Async sentSseMessage Error，clientId = {},error={}", emitter.getSseId(), e.getMessage());
			emitter.completeWithError(e); // 发生错误时，关闭连接并报错
			SSE_CACHE.remove(emitter.getSseId());
			emitter.setDone(true);
		} finally {
			if (is != null) {
				is.close();
			}
			if (reader != null) {
				reader.close();
			}
		}
	}

	public void sseSendMessageOrigin(String message, SseEmitterUTF8 sseEmitterUTF8) {
		try {
			if (sseEmitterUTF8.isDone()) {
				sseEmitterUTF8.send(message, MediaType.TEXT_PLAIN);
			}
		} catch (Exception e) {
			sseEmitterUTF8.completeWithError(e);
			log.info("SSE sseSendMessage1 Error，clientId = {},error={}", sseEmitterUTF8.getSseId(), e.getMessage());
			SSE_CACHE.remove(sseEmitterUTF8.getSseId());
			sseEmitterUTF8.setDone(true);
		}
	}
}
